package com.jspx.txweb.evasive;

import com.jspx.boot.EnvFactory;
import com.jspx.boot.conf.JarDefaultConfig;
import com.jspx.boot.environment.Environment;
import com.jspx.boot.environment.EnvironmentTemplate;
import com.jspx.io.AbstractRead;
import com.jspx.io.AutoReadTextFile;
import com.jspx.txweb.config.ResultConfigBean;
import com.jspx.utils.ArrayUtil;
import com.jspx.utils.FileUtil;
import com.jspx.utils.StringUtil;
import com.jspx.utils.XMLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URL;
import java.util.*;

/**
 * Created by Administrator on 2017/6/14.
 *
 */
public class EvasiveConfiguration implements Configuration {
    final static private Logger log = LoggerFactory.getLogger(EvasiveConfiguration.class);
    private List<EvasiveRule> evasiveRuleList = new ArrayList<EvasiveRule>();
    private List<ResultConfigBean> resultConfigList =  new ArrayList<ResultConfigBean>();
    private String[] whiteList =  null;
    private String[] blackList =  null;
    //黑名单
    private List<String> blacklist =  new ArrayList<String>();
    private String[] insecureUrlKeys = null;
    private String[] insecureQueryStringKeys = null;
    private List<QueryBlack> queryBlackRuleList = new ArrayList<QueryBlack>();
    //包含的文件,用作判断，如果已经载入的文件将不再载入
    private String[] includeFiles = null;
    //默认载入的文件名
    private String fileName = "evasive.xml";

    public List<EvasiveRule> getEvasiveRuleList()
    {
        return evasiveRuleList;
    }


    public String[] getWhiteList()
    {
        return whiteList;
    }

    public String[] getBlackList()
    {
        return blackList;
    }

    public List<QueryBlack> getQueryBlackRuleList()
    {
        return queryBlackRuleList;
    }

    public List<ResultConfigBean> getResultConfigList()
    {
        return resultConfigList;
    }

    public String[] getInsecureUrlKeys()
    {
        return insecureUrlKeys;
    }

    public String[] getInsecureQueryStringKeys()
    {
        return insecureQueryStringKeys;
    }

    private static Configuration instance =  new EvasiveConfiguration();
    public static Configuration getInstance() {
        return instance;
    }
    private EvasiveConfiguration() {

    }

    public String getFileName()
    {
        return fileName;
    }


    public void setFileName(String fileName) {
        this.fileName = fileName;
        if (!StringUtil.isNULL(this.fileName))
        try {
            reload();
        } catch (Exception e) {
            log.error(" evasive reload config fail",e);
            e.printStackTrace();
        }
    }


    public void reload() throws Exception
    {
        EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
        boolean useEvasive = envTemplate.getBoolean(Environment.useEvasive);
        if (!useEvasive) return;

        //默认环境
        String defaultFile = fileName;
        if (!FileUtil.isFileExist(defaultFile)) {

            String temp = envTemplate.getString(Environment.defaultPath);
            if (StringUtil.isNULL(temp)) {
                temp = StringUtil.empty;
            }
            defaultFile = temp + fileName;
        }

        if (!FileUtil.isFileExist(defaultFile)) {
            URL url = JarDefaultConfig.class.getResource("/" + fileName);
            if (url != null) {
                defaultFile = url.getPath();
            }
        }

        if (!FileUtil.isFileExist(defaultFile)) {
            URL url = JarDefaultConfig.class.getResource(fileName);
            if (url != null) {
                defaultFile = url.getPath();
            }
        }

        if (!FileUtil.isFileExist(defaultFile)) {
            throw new Exception("not find evasive config file:" + defaultFile);
        }

        evasiveRuleList.clear();
        fileName = defaultFile;
        includeFiles = null;
        String defaultPath = FileUtil.getParentPath(fileName);
        if (StringUtil.isNULL(defaultPath)) defaultPath = envTemplate.getString(Environment.defaultPath);
        String[] includeFixedFiles = new String[1];
        includeFixedFiles[0] = fileName;
        readIncludeFile(defaultPath, includeFixedFiles);

    }

    /**
     * @param defaultPath     默认路径
     * @param include         包含的路径
     * @throws Exception 异常
     */
    private void readIncludeFile(String defaultPath, final String[] include) throws Exception {
        if (include == null) return;
        for (String file : include) {

            if (StringUtil.isNULL(file)) continue;

            log.info("evasive load config file:" + file);

            String defaultFile;
            if (FileUtil.isFileExist(file)) defaultFile = file;
            else defaultFile = defaultPath + file;

            if (!FileUtil.isFileExist(defaultFile)) {
                URL url = Environment.class.getResource("/" + file);
                if (url != null) {
                    defaultFile = url.getPath();
                }
            }
            if (!FileUtil.isFileExist(defaultFile)) {
                URL url = Environment.class.getResource(file);
                if (url != null) {
                    defaultFile = url.getPath();
                }
            }
            if (!FileUtil.isFileExist(defaultFile)) continue;

            File readFile = new File(defaultFile);
            if (ArrayUtil.inArray(includeFiles, readFile.getAbsolutePath(), true)) continue;
            includeFiles = ArrayUtil.add(includeFiles, readFile.getAbsolutePath());

            AbstractRead ar = new AutoReadTextFile();
            ar.setFile(readFile);
            ReadEvasiveRuleConfig readConfig = new ReadEvasiveRuleConfig();
            if (XMLUtil.parseXmlString(readConfig,ar.getContent()))
            {
                String[] includeFixedFiles = null;
                String[] iFiles = readConfig.getInclude();

                evasiveRuleList.addAll(readConfig.getEvasiveRuleList());
                this.insecureUrlKeys = ArrayUtil.join(this.insecureUrlKeys,readConfig.getInsecureUrlKeys());
                this.insecureQueryStringKeys = ArrayUtil.join(this.insecureQueryStringKeys,readConfig.getInsecureQueryStringKeys());
                this.whiteList = ArrayUtil.join(this.whiteList,readConfig.getWhiteList());
                this.blackList = ArrayUtil.join(this.blackList,readConfig.getBlackList());
                this.queryBlackRuleList.addAll(readConfig.getQueryBlackRuleList());
                this.resultConfigList = readConfig.getResultConfigList();
                if (iFiles != null)
                {
                    for (String mif : iFiles) {
                        if (FileUtil.isPatternFileName(mif)) {
                            File[] fileName = FileUtil.getPatternFiles(defaultPath, mif);
                            for (File f : fileName) {
                                includeFixedFiles = ArrayUtil.add(includeFixedFiles, f.getName());
                            }
                        } else includeFixedFiles = ArrayUtil.add(includeFixedFiles, mif);
                    }
                }

                readIncludeFile(defaultPath, includeFixedFiles);
            } else {
                log.error("evasive load config file xml error:" + file);
            }
        }
    }

    public void shutdown()
    {
        evasiveRuleList.clear();
        queryBlackRuleList.clear();
        whiteList = null;
        blackList = null;
    }
}

